<html lang="zh-CN"><head><meta charset="UTF-8"><style>.nodata  main {width:1000px;margin: auto;}</style></head><body class="nodata " style=""><div class="main_father clearfix d-flex justify-content-center " style="height:100%;"> <div class="container clearfix " id="mainBox"><main><div class="blog-content-box">
<div class="article-header-box">
<div class="article-header">
<div class="article-title-box">
<h1 class="title-article" id="articleContentId">(C卷,100分)- API集群负载统计（Java & JS & Python & C）</h1>
</div>
</div>
</div>
<div id="blogHuaweiyunAdvert"></div>

        <div id="article_content" class="article_content clearfix">
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css">
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-044f2cf1dc.css">
                <div id="content_views" class="htmledit_views">
                    <h4 id="main-toc">题目描述</h4> 
<p>某个产品的RESTful API集合部署在服务器集群的多个节点上&#xff0c;近期对客户端访问日志进行了采集&#xff0c;需要统计各个API的访问频次&#xff0c;根据热点信息在服务器节点之间做负载均衡&#xff0c;现在需要实现热点信息统计查询功能。</p> 
<p>RESTful API是由多个层级构成&#xff0c;层级之间使用 / 连接&#xff0c;如 /A/B/C/D 这个地址&#xff0c;A属于第一级&#xff0c;B属于第二级&#xff0c;C属于第三级&#xff0c;D属于第四级。</p> 
<p>现在负载均衡模块需要知道给定层级上某个名字出现的频次&#xff0c;未出现过用0表示&#xff0c;实现这个功能。</p> 
<p></p> 
<h4 id="%E8%BE%93%E5%85%A5%E6%8F%8F%E8%BF%B0">输入描述</h4> 
<p>第一行为N&#xff0c;表示访问历史日志的条数&#xff0c;0 &#xff1c; N ≤ 100。</p> 
<p>接下来N行&#xff0c;每一行为一个RESTful API的URL地址&#xff0c;约束地址中仅包含英文字母和连接符 / &#xff0c;最大层级为10&#xff0c;每层级字符串最大长度为10。</p> 
<p>最后一行为层级L和要查询的关键字。</p> 
<p></p> 
<h4 id="%E8%BE%93%E5%87%BA%E6%8F%8F%E8%BF%B0">输出描述</h4> 
<p>输出给定层级上&#xff0c;关键字出现的频次&#xff0c;使用完全匹配方式&#xff08;大小写敏感&#xff09;。</p> 
<p></p> 
<h4 id="%E7%94%A8%E4%BE%8B">用例</h4> 
<table border="1" cellpadding="1" cellspacing="1" style="width:500px;"><tbody><tr><td style="width:86px;">输入</td><td style="width:412px;">5<br /> /huawei/computing/no/one<br /> /huawei/computing<br /> /huawei<br /> /huawei/cloud/no/one<br /> /huawei/wireless/no/one<br /> 2 computing</td></tr><tr><td style="width:86px;">输出</td><td style="width:412px;">2</td></tr><tr><td style="width:86px;">说明</td><td style="width:412px;">在第二层级上&#xff0c;computing出现了2次&#xff0c;因此输出2</td></tr></tbody></table> 
<table border="1" cellpadding="1" cellspacing="1" style="width:500px;"><tbody><tr><td style="width:86px;">输入</td><td style="width:412px;">5<br /> /huawei/computing/no/one<br /> /huawei/computing<br /> /huawei<br /> /huawei/cloud/no/one<br /> /huawei/wireless/no/one<br /> 4 two</td></tr><tr><td style="width:86px;">输出</td><td style="width:412px;">0</td></tr><tr><td style="width:86px;">说明</td><td style="width:412px;">存在第四层级的URL上&#xff0c;没有出现two&#xff0c;因此频次是0</td></tr></tbody></table> 
<p> </p> 
<h4 id="%E9%A2%98%E7%9B%AE%E8%A7%A3%E6%9E%90">题目解析</h4> 
<p>本题应该就是一个逻辑模拟题&#xff0c;以及考察集合的应用。</p> 
<p></p> 
<p>本题的难度主要在于数据结构的定义&#xff0c;我们需要按照下图所示方式&#xff0c;对各层级的关键字进行统计</p> 
<p><img alt="" height="211" src="https://img-blog.csdnimg.cn/direct/8ea5b19fed43424385c3f8d912d521ca.png" width="844" /></p> 
<blockquote> 
 <p><strong>[</strong><br />   {},                                                                  // 层级0<br />   {&#34;huawei&#34;: 5},                                                // 层级1<br />   {&#34;computing&#34;: 2&#xff0c;&#34;cloud&#34;: 1&#xff0c;&#34;wireless&#34;: 1}, // 层级2<br />   {&#34;no&#34;: 3},                                                        // 层级3<br />   {&#34;one&#34;: 3}                                                       // 层级4<br /><strong> ]</strong></p> 
</blockquote> 
<p>外层是一个数组&#xff08;数组索引就是层级号&#xff09;&#xff0c;数组元素是一个map结构&#xff08;key是关键字&#xff0c;val是关键字在对应层级出现次数&#xff09;</p> 
<p>我们按照这种数据结构收集各条日志URL的组成关键字&#xff0c;就能快速的找到指定层级&#xff08;通过数组索引&#xff09;下的指定关键字&#xff08;通过map结构的key&#xff09;的出现频次&#xff08;map结构的val&#xff09;</p> 
<p></p> 
<p>更多细节信息&#xff0c;请看代码注释。</p> 
<p></p> 
<h4 id="%E7%AE%97%E6%B3%95%E6%BA%90%E7%A0%81">JS算法源码</h4> 
<pre><code class="language-javascript">const rl &#61; require(&#34;readline&#34;).createInterface({ input: process.stdin });
var iter &#61; rl[Symbol.asyncIterator]();
const readline &#61; async () &#61;&gt; (await iter.next()).value;

void (async function () {
  // 访问历史日志的条数
  const n &#61; parseInt(await readline());

  // 记录各层级上各关键字出现的频次
  const cnts &#61; [];

  // 遍历历史日志
  for (let i &#61; 0; i &lt; n; i&#43;&#43;) {
    // 将日志按照 &#34;/&#34; 分割&#xff0c;注意split函数会将 &#34;/a/b/c&#34; 会分割出数组 [&#34;&#34;, &#34;a&#34;, &#34;b&#34;, &#34;c&#34;]&#xff0c;因此a,b,c的层级就是其索引值
    const urlComponents &#61; (await readline()).split(&#34;/&#34;);

    // 遍历url的各层级
    for (let level &#61; 0; level &lt; urlComponents.length; level&#43;&#43;) {
      const urlComponent &#61; urlComponents[level];

      // 如果cnts不存在对于层级
      if (cnts.length &lt;&#61; level) {
        // 则创建对应层级
        cnts.push({});
      }

      // 在对应层级上将对应关键字出现次数&#43;1
      if (cnts[level][urlComponent]) {
        cnts[level][urlComponent] &#43;&#61; 1;
      } else {
        cnts[level][urlComponent] &#61; 1;
      }
    }
  }

  // 要查询的给定层级, 要查询的关键字
  let [tar_level, tar_urlComponent] &#61; (await readline()).split(&#34; &#34;);

  tar_level &#61; parseInt(tar_level);

  if (tar_level &gt;&#61; cnts.length) {
    // 如果要查询的层级超出了统计范围&#xff0c;则返回0
    console.log(0);
  } else {
    // 获取对应层级上对应关键字出现的频次&#xff0c;如果没有出现&#xff0c;则返回0
    if (cnts[tar_level][tar_urlComponent]) {
      console.log(cnts[tar_level][tar_urlComponent]);
    } else {
      console.log(0);
    }
  }
})();
</code></pre> 
<p></p> 
<h4 style="background-color:transparent;">Java算法源码</h4> 
<pre><code class="language-java">import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc &#61; new Scanner(System.in);

    // 访问历史日志的条数
    int n &#61; sc.nextInt();

    // 记录各层级上各关键字出现的频次
    ArrayList&lt;HashMap&lt;String, Integer&gt;&gt; cnts &#61; new ArrayList&lt;&gt;();

    // 遍历历史日志
    for (int i &#61; 0; i &lt; n; i&#43;&#43;) {
      // 将日志按照 &#34;/&#34; 分割&#xff0c;注意split函数会将 &#34;/a/b/c&#34; 会分割出数组 [&#34;&#34;, &#34;a&#34;, &#34;b&#34;, &#34;c&#34;]&#xff0c;因此a,b,c的层级就是其索引值
      String[] urlComponents &#61; sc.next().split(&#34;/&#34;);

      // 遍历url的各层级
      for (int level &#61; 0; level &lt; urlComponents.length; level&#43;&#43;) {
        String urlComponent &#61; urlComponents[level];

        // 如果cnts不存在对于层级
        if (cnts.size() &lt;&#61; level) {
          // 则创建对应层级
          cnts.add(new HashMap&lt;&gt;());
        }

        // 获取对应层级
        HashMap&lt;String, Integer&gt; map &#61; cnts.get(level);
        // 在对应层级上将对应关键字出现次数&#43;1
        map.put(urlComponent, map.getOrDefault(urlComponent, 0) &#43; 1);
      }
    }

    // 要查询的给定层级
    int tar_level &#61; sc.nextInt();
    // 要查询的关键字
    String tar_urlComponent &#61; sc.next();

    if (tar_level &gt;&#61; cnts.size()) {
      // 如果要查询的层级超出了统计范围&#xff0c;则返回0
      System.out.println(0);
    } else {
      // 获取对应层级上对应关键字出现的频次&#xff0c;如果没有出现&#xff0c;则返回0
      System.out.println(cnts.get(tar_level).getOrDefault(tar_urlComponent, 0));
    }
  }
}
</code></pre> 
<p> </p> 
<h4 style="background-color:transparent;">Python算法源码</h4> 
<pre><code class="language-python"># 访问历史日志的条数
n &#61; int(input())

# 记录各层级上各关键字出现的频次
cnts &#61; []

# 遍历历史日志
for _ in range(n):
    # 将日志按照 &#34;/&#34; 分割&#xff0c;注意split函数会将 &#34;/a/b/c&#34; 会分割出数组 [&#34;&#34;, &#34;a&#34;, &#34;b&#34;, &#34;c&#34;]&#xff0c;因此a,b,c的层级就是其索引值
    urlComponents &#61; input().split(&#34;/&#34;)

    # 遍历url的各层级
    for level in range(len(urlComponents)):
        urlComponent &#61; urlComponents[level]

        # 如果cnts不存在对于层级
        if level &gt;&#61; len(cnts):
            # 则创建对应层级
            cnts.append({})

        # 获取对应层级
        cnts[level][urlComponent] &#61; cnts[level].get(urlComponent, 0) &#43; 1

# 要查询的给定层级, 要查询的关键字
tar_level, tar_urlComponent &#61; input().split()

tar_level &#61; int(tar_level)

if tar_level &gt;&#61; len(cnts):
    # 如果要查询的层级超出了统计范围&#xff0c;则返回0
    print(0)
else:
    # 获取对应层级上对应关键字出现的频次&#xff0c;如果没有出现&#xff0c;则返回0
    print(cnts[tar_level].get(tar_urlComponent, 0))
</code></pre> 
<p></p> 
<h4 style="background-color:transparent;">C算法源码</h4> 
<pre><code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;

#define MAX_URL_LENGTH 150
#define MAX_LEVELS 11

typedef struct ListNode {
    char urlComponent[11];
    int count;
    struct ListNode *next;
} ListNode;

ListNode *new_ListNode(char *urlComponent) {
    ListNode *node &#61; (ListNode *) malloc(sizeof(ListNode));
    strcpy(node-&gt;urlComponent, urlComponent);
    node-&gt;count &#61; 1;
    return node;
}

typedef struct LinkedList {
    int size;
    ListNode *head;
    ListNode *tail;
} LinkedList;

LinkedList *new_LinkedList() {
    LinkedList *link &#61; (LinkedList *) malloc(sizeof(LinkedList));
    link-&gt;size &#61; 0;
    link-&gt;head &#61; NULL;
    link-&gt;tail &#61; NULL;
    return link;
}

void add_LinkedList(LinkedList *link, char *urlComponent) {
    ListNode *cur &#61; link-&gt;head;

    while (cur !&#61; NULL) {
        if (strcmp(cur-&gt;urlComponent, urlComponent) &#61;&#61; 0) {
            cur-&gt;count&#43;&#43;;
            return;
        }
        cur &#61; cur-&gt;next;
    }

    ListNode *node &#61; new_ListNode(urlComponent);
    node-&gt;next &#61; link-&gt;head;
    link-&gt;head &#61; node;
    link-&gt;size&#43;&#43;;
}

int get_LinkedList(LinkedList *link, char *urlComponent) {
    ListNode *cur &#61; link-&gt;head;

    while (cur !&#61; NULL) {
        if (strcmp(cur-&gt;urlComponent, urlComponent) &#61;&#61; 0) {
            return cur-&gt;count;
        }
        cur &#61; cur-&gt;next;
    }

    return 0;
}

int main() {
    // 访问历史日志的条数
    int n;
    scanf(&#34;%d&#34;, &amp;n);
    getchar();

    // 记录各层级上各关键字出现的频次
    LinkedList *cnts[MAX_LEVELS] &#61; {NULL};
    int cnts_size &#61; 1;

    // 遍历历史日志
    for (int i &#61; 0; i &lt; n; i&#43;&#43;) {
        char url[MAX_URL_LENGTH];
        gets(url);

        // 按照 &#34;/&#34; 分割url&#xff0c;比如 &#34;/a/b/c&#34; &#xff0c;C语言的strtok函数第一次就会解析出&#34;a&#34;&#xff0c;而”a“的层级是1&#xff0c;因此level从1开始计数
        int level &#61; 1;
        char *token &#61; strtok(url, &#34;/&#34;);
        while (token !&#61; NULL) {

            // 如果cnts不存在对于层级
            if (level &gt;&#61; cnts_size) {
                // 则创建对应层级
                cnts[cnts_size&#43;&#43;] &#61; new_LinkedList();
            }

            // 将对应层级上将对应关键字出现次数&#43;1
            add_LinkedList(cnts[level], token);

            level&#43;&#43;;
            token &#61; strtok(NULL, &#34;/&#34;);
        }
    }

    // 要查询的给定层级
    int tar_level;
    // 要查询的关键字
    char tar_urlComponent[11];

    scanf(&#34;%d %s&#34;, &amp;tar_level, tar_urlComponent);

    if (tar_level &gt;&#61; cnts_size) {
        // 如果要查询的层级超出了统计范围&#xff0c;则返回0
        puts(&#34;0&#34;);
    } else {
        // 获取对应层级上对应关键字出现的频次&#xff0c;如果没有出现&#xff0c;则返回0
        printf(&#34;%d\n&#34;, get_LinkedList(cnts[tar_level], tar_urlComponent));
    }

    return 0;
}</code></pre> 
<p></p>
                </div>
        </div>
        <div id="treeSkill"></div>
        <div id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"></div>
    <script>
  $(function() {
    setTimeout(function () {
      var mathcodeList = document.querySelectorAll('.htmledit_views img.mathcode');
      if (mathcodeList.length > 0) {
        for (let i = 0; i < mathcodeList.length; i++) {
          if (mathcodeList[i].naturalWidth === 0 || mathcodeList[i].naturalHeight === 0) {
            var alt = mathcodeList[i].alt;
            alt = '\\(' + alt + '\\)';
            var curSpan = $('<span class="img-codecogs"></span>');
            curSpan.text(alt);
            $(mathcodeList[i]).before(curSpan);
            $(mathcodeList[i]).remove();
          }
        }
        MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
      }
    }, 1000)
  });
</script>
</div></html>